import type { FiledContextProps } from '../Context/FieldContext';
import type { FieldError, InternalValidateOptions, Rule } from './ValidateType';
import type {
  FormInstance,
  InternalNamePath,
  NamePath,
  RecursivePartial,
  Store,
  StoreValue,
} from './index';
// >>>>>> Info
interface ValueUpdateInfo {
  type: 'valueUpdate';
  source: 'internal' | 'external';
}

interface ValidateFinishInfo {
  type: 'validateFinish';
}

interface ResetInfo {
  type: 'reset';
}

interface RemoveInfo {
  type: 'remove';
}

interface SetFieldInfo {
  type: 'setField';
  data: Map<string, FieldData>;
}

interface DependenciesUpdateInfo {
  type: 'dependenciesUpdate';
  /**
   * Contains all the related `InternalNamePath[]`.
   * a <- b <- c : change `a`
   * relatedFields=[a, b, c]
   */
  // relatedFields: InternalNamePath[];
}

export type NotifyInfo =
  | ValueUpdateInfo
  | ValidateFinishInfo
  | ResetInfo
  | RemoveInfo
  | SetFieldInfo
  | DependenciesUpdateInfo;

export type ValuedNotifyInfo = NotifyInfo & {
  store: Store;
};

export interface FieldEntity {
  onStoreChange: (
    prevStore: Store,
    updateNamePathList: InternalNamePath[],
    info: ValuedNotifyInfo,
  ) => void;
  isFieldDirty: () => boolean;
  isFieldListField: () => boolean;
  isFieldList: () => boolean;
  validateRules: (options: InternalValidateOptions) => Promise<FieldError>;
  getMeta: () => Meta;
  getNamePath: () => InternalNamePath;
  getErrors: () => string[];
  getWarnings: () => string[];
}

export type ShouldUpdate<Values = any> =
  | boolean
  | ((
      prevValues: Values,
      nextValues: Values,
      info: { source?: string },
    ) => boolean);

export interface ChildProps {
  [property: string]: any;
}

export type MetaEvent = Meta & { destroy?: boolean };
export interface InternalFieldProps<Values = any> {
  name: InternalNamePath | undefined;
  children:
    | React.ReactNode
    | ((
        control: ChildProps,
        meta: Meta,
        form: FormInstance,
      ) => React.ReactNode);
  rules?: Rule[];
  dependencies?: NamePath[];
  initialValue?: RecursivePartial<Values>;
  trigger?: string;
  validateTrigger?: string | string[];
  shouldUpdate?: ShouldUpdate<Values>; // typeof shouldUpdate ===  'function'时 会在 Field.onChange -- onStoreChange 执行，而 typeof shouldUpdate ===  true时 除此之外还会在 componentDidMount之后--reRender,
  isListField?: boolean;
  isList?: boolean;
  fieldContext: FiledContextProps;
  messageVariables?: Record<string, string>;
  validateFirst?: boolean | 'parallel';
  valuePropName?: string;
  onMetaChange?: (meta: MetaEvent) => void;
}

export interface FieldProps<Values = any>
  extends Omit<InternalFieldProps, 'name' | 'fieldContext'> {
  name?: NamePath;
}

export type FieldCombineEntity = FieldEntity & { props: InternalFieldProps };

export interface Meta {
  touched: boolean;
  validating: boolean;
  errors: React.ReactNode[];
  warnings: React.ReactNode[];
  name: InternalNamePath;
  validated: boolean;
}

export interface InternalFieldData extends Meta {
  value: StoreValue;
}

/**
 * Used by `setFields` config
 */
export interface FieldData extends Partial<Omit<InternalFieldData, 'name'>> {
  name: NamePath;
}
